﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ArrayBlockQueue
{
    class Program
    {
        static void Main(string[] args)
        {
            var queue = new ArrayBlockingQueue<int>(2);

            var t1 = new Thread(() =>
            {
                for (var i = 0; i < 3; i++)
                {
                    queue.Enqueue(i);
                    Thread.Sleep(1000);
                }
            });

            var t2 = new Thread(() =>
            {
                Thread.Sleep(5000);
                for (var i = 0; i < 3; i++)
                {
                    var d = queue.Dequeue();
                    Thread.Sleep(5000);
                }
            });
            
            t2.Start();

            t1.Start();

            Console.ReadLine();
        }
    }

    class ArrayBlockingQueue<T>
    {
        private T[] items;
        private AutoResetEvent getEvent;
        private AutoResetEvent setEvent;
        private object syncObject;

        private int getIndex;
        private int setIndex;
        private int count;

        public ArrayBlockingQueue(int size)
        {
            getEvent = new AutoResetEvent(false);
            setEvent = new AutoResetEvent(false);
            items = new T[size];
            syncObject = new object();
        }

        public void Enqueue(T data)
        {
            
                try
                {
                    Console.WriteLine("正在Enqueue对象.");
                    while (count == items.Length)
                    {
                        Console.WriteLine("队列满了. 阻塞Enqueue线程.");
                        setEvent.WaitOne();
                    }

                    Console.WriteLine("Euqueue数据完成: {0}", data);
                    items[setIndex] = data;
                    Interlocked.Increment(ref setIndex);
                    Interlocked.Increment(ref count);

                    if (setIndex == items.Length)
                    {
                        setIndex = 0;
                    }
                    Console.WriteLine("唤醒Dequeue线程");
                    getEvent.Set();

                }
                catch (Exception ex)
                {
                    Console.WriteLine("Enqueue 异常:" + ex.Message);
                }
        }

        public T Dequeue()
        {
            T data = default(T);
            
                try
                {
                    Console.WriteLine("#正在Dequeue对象");
                    while (count == 0)
                    {
                        Console.WriteLine("#队列是空的. 阻塞Dequeue线程.");
                        getEvent.WaitOne();
                    }

                    data = items[getIndex];
                    Console.WriteLine("#Dequeue对象完成: {0}", data);
                    Interlocked.Increment(ref getIndex);
                    Interlocked.Decrement(ref count);

                    if (getIndex == items.Length)
                    {
                        getIndex = 0;
                    }
                    Console.WriteLine("#唤醒Enqueue线程");
                    setEvent.Set();

                }
                catch (Exception ex)
                {
                    Console.WriteLine("Dequeue 异常:" + ex.Message);
                }

                return data;

        }
    }
}
